#pragma once
/**
 * @file Connection.hpp
 * @author your name (you@domain.com)
 * @brief 对一个通信连接的所有操作，都将通过此模块完成
 * 功能设计：
 *      1、套接字管理，套接字的操作
 *      2、连接事件管理，可读 可写 错误 挂断 任意
 *      3、缓冲区管理
 *      4、协议上下文管理，记录请求数据的处理过程
 *
 * 提供接口：
 * - 发送数据，将数据放入发送缓冲区，同时启动写事件
 * - 关闭连接，关闭一个连接，实际释放连接之前，要将缓冲区的数据进行处理
 * - 启动非活跃超时销毁/取消非活跃超时销毁
 * - 协议切换
 * @version 0.1
 * @date 2024-10-12
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <cstdint>
#include "Channel.hpp"
#include "Buffer.hpp"
#include "../common/Socket.hpp"
#include "../common/Any.hpp"
#include "EventLoop.hpp"


enum class ConnStatu
{
    DISCONNECTED, // 连接已关闭状态
    CONNECTING,   // 连接刚建立状态，待处理状态
    CONNECTED,    // 连接已完成 可以进行数据通信
    DISCONNECTING // 连接待关闭状态
};

class EventLoop; /*前置声明 当一个连接创建时 就要绑定到一个EventLoop上*/
class Connection : public std::enable_shared_from_this<Connection>
{
public:
    using PtrConnection = std::shared_ptr<Connection>;
    using ConnectedCallBack = std::function<void(const PtrConnection &)>;
    using MessageCallBack = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallBack = std::function<void(const PtrConnection &)>;
    using AnyEventCallBack = std::function<void(const PtrConnection &)>;

public:
    
    Connection(EventLoop *loop, uint64_t conn_id, int sock_fd) : loop_(loop),
                                                                 conn_id_(conn_id),
                                                                 sock_fd_(sock_fd),
                                                                 socket_(sock_fd),
                                                                 channel_(loop, sock_fd),
                                                                 statu_(ConnStatu::CONNECTING)
    {
        channel_.set_close_callback(std::bind(&Connection::handle_close, this));
        channel_.set_event_callback(std::bind(&Connection::handle_event, this));
        channel_.set_read_callback(std::bind(&Connection::handle_read, this));
        channel_.set_write_callback(std::bind(&Connection::handle_write, this));
        channel_.set_error_callback(std::bind(&Connection::handle_error, this));

        // channel 的启动读事件监控 不在构造函数内完成 否则会导致定时任务出问题
        // 因为如果在此处开启了读事件监控，如果立即来了读事件 此时调用handle_read会接着调用handle_event推迟定时任务，但由于还没有设置定时任务，因此会出错
    }
    ~Connection()
    {
        LOG_DEBUG("release connection id = {}", conn_id_);
    }

    int get_fd();
    int get_connect_id();
    Any *get_context();
    void set_context(const Any &context);
    void set_connected_callback(const ConnectedCallBack &cb);
    void set_message_callback(const MessageCallBack &cb);
    void set_closed_callback(const ClosedCallBack &cb);
    void set_anyevent_callback(const AnyEventCallBack &cb);
    void set_server_closed_callback(const ClosedCallBack &cb);
    void established();
    bool is_connected();

    void send(const char *data, size_t len);         // 发送数据，将数据放到发送缓冲区，启动写事件监控
    void shutdown();                           // 提供给组件使用者的关闭接口-并不会实际关闭，要等待所有数据处理完毕才会关闭
    void enable_inactive_release(int timeout); /*启动非活跃销毁，并定义多长时间无通信 单位 s*/
    void disable_incactive_release();
    void upgrade(const Any &context, const ConnectedCallBack &conn, const MessageCallBack &mess, const ClosedCallBack &close, const AnyEventCallBack &any); // 协议切换：重置上下文和阶段性处理函数
private:
    void handle_read();  // 描述符可读事件后 调用此函数 接受socket数据放入接受缓冲区 然后调用message_callback
    void handle_write(); // 描述符可写事件触发的函数，将发送缓冲区的数据进行发送
    void handle_close();
    void handle_error();
    void handle_event();

    void estabished_in_loop(); // 连接获取之后 所处的状态下要进行的各种设置 给channel设置事件回调 并启动读监控 调用连接完成回调函数
    void send_in_loop(Buffer::SharedPtr buffer);
    void release(){
        loop_->queue_in_loop(std::bind(&Connection::release_in_loop, this));
    }
    void release_in_loop(); // 实际释放接口
    void shutdown_in_loop();
    void enable_inactive_release_in_loop(int timeout);
    void disable_incactive_release_in_loop();
    void upgrade_in_loop(const Any &context, const ConnectedCallBack &conn, const MessageCallBack &mess, const ClosedCallBack &close, const AnyEventCallBack &any);

private:
    uint64_t conn_id_;             // 连接的唯一ID， 方便进行连接管理； 此处直接使用定时器ID作为连接的唯一ID
    ConnStatu statu_;              // 标记连接状态
    bool enable_inactive_release_; // 连接是否启动非活跃销毁，默认不销毁
    int sock_fd_;                  // 连接关联的文件描述符
    Socket socket_;                // 套接字操作管理
    Channel channel_;              // 连接的事件管理
    Buffer inbuffer_;
    Buffer outbuffer_;
    Any context_; // 请求的接收处理上下文

    /*这些回调函数是让服务器模块设置，即组件使用者->服务器模块->回调函数*/
    ConnectedCallBack connected_callback_;
    MessageCallBack message_callback_;
    ClosedCallBack closed_callabck_;
    ClosedCallBack server_closed_callabck_; // 组件内连接关闭回调 组件内设置 服务器组件会把所有连接管理起来 一旦某个连接要关闭 就应该从管理的地方移除掉自己的信息
    AnyEventCallBack anyevent_callback_;

    /*标识连接属于哪个EventLoop*/
    EventLoop *loop_;
};

void Connection::handle_read()
{
    // 先接收数据 再调用用户传入的回调
    char buf[65536];
    ssize_t ret = socket_.recv_nonblock(buf, 65535);
    if (ret < 0)
    {
        // LOG_DEBUG("ret <= 0");
        // 出错了 || 连接断开 返回-1
        shutdown_in_loop();
        return;
    }

    inbuffer_.write(buf, ret); // 写一定会将写偏移移动

    // 调用 message_callback
    if (inbuffer_.get_readable_size() > 0)
        message_callback_(shared_from_this(), &inbuffer_);
}

void Connection::handle_write()
{
    
    ssize_t ret = socket_.send_nonblock(outbuffer_.get_reader_addr(), outbuffer_.get_readable_size());
    if (ret < 0)
    {
        // 发送出错，将剩余数据全部发送后关闭连接
        if (inbuffer_.get_readable_size() > 0)
        {
            message_callback_(shared_from_this(), &inbuffer_);
        }
        // LOG_DEBUG("handle_write 调用了一次 release");  
        return release();
    }

    // 将读偏移向后移动
    outbuffer_.move_read_offset(ret);

    // 如果本次发送完毕缓冲区已经没有数据要发送 则关闭写事件监控
    if (outbuffer_.get_readable_size() == 0)
    {
        channel_.disable_write_event();
        // 如果当前是连接待关闭状态 直接关闭连接
        if (statu_ == ConnStatu::DISCONNECTING)
        {
            // LOG_DEBUG("当前状态为待关闭 要调用release_in_loop()");
            // LOG_TRACE("handle_write 调用了一次 release");  
            return release();
        }
    }
}

void Connection::handle_close()
{
    // 连接挂断 套接字就无法进行操作了 所以有数据就处理一下 处理完毕关闭连接
    if (inbuffer_.get_readable_size() > 0)
    {
        message_callback_(shared_from_this(), &inbuffer_);
    }
    // LOG_DEBUG("handler close 调用了一次 release");
    return release();
}

void Connection::handle_error()
{
    handle_close();
}

void Connection::estabished_in_loop()
{
    // 1 修改连接状态   可能立即会有事件 如果启动了非活跃销毁
    assert(statu_ == ConnStatu::CONNECTING);
    statu_ = ConnStatu::CONNECTED;
    // 2 启动读事件监控
    channel_.enable_read_event();
    // 3 调用回调函数
    if (connected_callback_)
        connected_callback_(shared_from_this());
}

// 非实际发送接口 只是将数据放入发送缓冲区 启动可写事件监控
void Connection::send_in_loop(Buffer::SharedPtr buffer)
{
    if (statu_ == ConnStatu::DISCONNECTED)
        return;

    outbuffer_.write_buffer_shared(buffer);

    if (!channel_.is_write_monitor())
    {
        channel_.enable_write_event();
    }
}

// 非实际连接释放操作 需要判断是否还有数据要发送
void Connection::shutdown_in_loop()
{
    // 设置连接半关闭状态
    statu_ = ConnStatu::DISCONNECTING;

    if (inbuffer_.get_readable_size() > 0)
    {
        if (message_callback_)
            message_callback_(shared_from_this(), &inbuffer_);
    }

    // 写入数据出错关闭 || 没有待发送数据 直接关闭
    if (outbuffer_.get_readable_size())
    {
        // LOG_DEBUG("outbuffer还有数据 当前是否启动了写监控 {}", channel_.is_write_monitor());
        if (!channel_.is_write_monitor())
        {
            channel_.enable_write_event();
        }
    }

    if (outbuffer_.get_readable_size() == 0)
    {
        // LOG_DEBUG("shutdown_in_loop 调用了一次 release");
        release();
    }
}

void Connection::upgrade_in_loop(const Any &context, const ConnectedCallBack &conn, const MessageCallBack &mess, const ClosedCallBack &close, const AnyEventCallBack &any)
{
    context_ = context;
    set_connected_callback(conn);
    set_message_callback(mess);
    set_closed_callback(close);
    set_anyevent_callback(any);
}

/* publci */

int Connection::get_fd()
{
    return sock_fd_;
}
int Connection::get_connect_id()
{
    return conn_id_;
}
Any *Connection::get_context()
{
    return &context_;
}
void Connection::set_context(const Any &context)
{
    context_ = context;
}
void Connection::set_connected_callback(const ConnectedCallBack &cb)
{
    connected_callback_ = cb;
}
void Connection::set_message_callback(const MessageCallBack &cb)
{
    message_callback_ = cb;
}
void Connection::set_closed_callback(const ClosedCallBack &cb)
{
    closed_callabck_ = cb;
}
void Connection::set_anyevent_callback(const AnyEventCallBack &cb)
{
    anyevent_callback_ = cb;
}

void Connection::set_server_closed_callback(const ClosedCallBack &cb)
{
    server_closed_callabck_ = cb;
}
bool Connection::is_connected()
{
    return statu_ == ConnStatu::CONNECTED;
}

/*---------------Connection中要依赖eventloop的进行操作-------------*/
void Connection::handle_event()
{
    //1 刷新连接的活跃度 延迟定时销毁任务
    if(enable_inactive_release_){
        loop_->delay_timer(conn_id_);// conn_id 在这里就相当于定时器id
    }

    //2 调用组件使用者的任意事件回调

    if(anyevent_callback_){
        anyevent_callback_(shared_from_this());
    }
}

void Connection::release_in_loop()
{

    // LOG_DEBUG("调用了 rlease_in_loop");
    //1 修改连接状态 将其置为 DISCONNECTED
    statu_ = ConnStatu::DISCONNECTED;
    //2 移除连接事件监控
    channel_.disable_all_event();
    //3 关闭描述符
    socket_.close();
    //4 如果当前定时器队列中 还有定时销毁任务 则取消任务
    if(loop_->has_timer(conn_id_))
    {
        loop_->cancel_timer(conn_id_);
    }


    //5 调用关闭回调函数 
    //- 先调用用户的关闭处理 ，防止移除connection后无法调用用户的回调函数
    //- 用户的关闭处理
    if(closed_callabck_) closed_callabck_(shared_from_this());
    //移除服务器内部管理的连接信息
    if(server_closed_callabck_) server_closed_callabck_(shared_from_this());
}

void Connection::enable_inactive_release_in_loop(int timeout)
{
    //1 将判断标志 enbale 置为true
    enable_inactive_release_ = true;
    //2 添加定时销毁任务(如果已经存在，刷新延迟即可)
    if(loop_->has_timer(conn_id_)){
        return loop_->delay_timer(conn_id_);
    }

    loop_->add_timer(conn_id_, timeout, std::bind(&Connection::release_in_loop, this));
}


void Connection::disable_incactive_release_in_loop()
{
    enable_inactive_release_ = false;
    if(loop_->has_timer(conn_id_)){
        loop_->cancel_timer(conn_id_);
    }
}


void Connection::established()
{
    loop_->run_in_loop(std::bind(&Connection::estabished_in_loop, this));
}


void Connection::send(const char *data, size_t len)
{
    //可能执行时 data执行的空间已经被释放了
    Buffer::SharedPtr buff = std::make_shared<Buffer>();
    buff->write(data, len);

    loop_->run_in_loop(std::bind(&Connection::send_in_loop, this, buff));
}

void Connection::shutdown()
{
    loop_->run_in_loop(std::bind(&Connection::shutdown_in_loop, this));
}


void Connection::enable_inactive_release(int timeout)
{
    loop_->run_in_loop(std::bind(&Connection::enable_inactive_release_in_loop, this ,timeout));
}

void Connection::disable_incactive_release()
{
    loop_->run_in_loop(std::bind(&Connection::disable_incactive_release_in_loop, this));
}


//此操作必须在当前loop的线程里执行！防止事件触发后 切换任务还未执行 而数据使用原协议进行处理
void Connection::upgrade(const Any &context, const ConnectedCallBack &conn, const MessageCallBack &mess, const ClosedCallBack &close, const AnyEventCallBack &any)
{ 
    loop_->run_in_loop(std::bind(&Connection::upgrade_in_loop, this, context, conn,mess,close,any));
}

